{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "from __future__ import absolute_import\n",
    "from __future__ import print_function\n",
    "import numpy as np\n",
    "np.random.seed(1337)  # for reproducibility\n",
    "\n",
    "\n",
    "import random\n",
    "from keras.models import Sequential, Model\n",
    "from keras.layers import Dense, Dropout, Input, Lambda, Activation, Flatten\n",
    "from keras.layers import Convolution2D, MaxPooling2D,BatchNormalization\n",
    "from keras.regularizers import l2, activity_l2\n",
    "from keras.optimizers import RMSprop\n",
    "from keras import backend as K\n",
    "from datasets.tidr import load_data\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def euclidean_distance(vects):\n",
    "    x, y = vects\n",
    "    return K.sqrt(K.sum(K.square(x - y), axis=1, keepdims=True))\n",
    "\n",
    "\n",
    "def eucl_dist_output_shape(shapes):\n",
    "    shape1, shape2 = shapes\n",
    "    return (shape1[0], 1)\n",
    "\n",
    "\n",
    "def contrastive_loss(y_true, y_pred):\n",
    "    '''Contrastive loss from Hadsell-et-al.'06\n",
    "    http://yann.lecun.com/exdb/publis/pdf/hadsell-chopra-lecun-06.pdf\n",
    "    '''\n",
    "    margin = 1\n",
    "    return K.mean(y_true * K.square(y_pred) + (1 - y_true) * K.square(K.maximum(margin - y_pred, 0)))\n",
    "\n",
    "\n",
    "def create_pairs(x, digit_indices):\n",
    "    '''Positive and negative pair creation.\n",
    "    Alternates between positive and negative pairs.\n",
    "    '''\n",
    "    pairs = []\n",
    "    labels = []\n",
    "    n = min([len(digit_indices[d]) for d in range(10)]) - 1\n",
    "    for d in range(10):\n",
    "        for i in range(n):\n",
    "            z1, z2 = digit_indices[d][i], digit_indices[d][i + 1]\n",
    "            pairs += [[x[z1], x[z2]]]\n",
    "            inc = random.randrange(1, 10)\n",
    "            dn = (d + inc) % 10\n",
    "            z1, z2 = digit_indices[d][i], digit_indices[dn][i]\n",
    "            pairs += [[x[z1], x[z2]]]\n",
    "            labels += [1, 0]\n",
    "    return np.array(pairs), np.array(labels)\n",
    "\n",
    "def create_compare(x_train, x_ref):\n",
    "    pairs = []\n",
    "    labels = []\n",
    "    for i in xrange(25):\n",
    "        for j in xrange(120):\n",
    "            pairs += [[x_train[120*i+j], x_ref[i]]]\n",
    "            \n",
    "    return np.array(pairs)\n",
    "\n",
    "\n",
    "\n",
    "def create_base_network(input_shape):\n",
    "    '''Base network to be shared (eq. to feature extraction).\n",
    "    '''\n",
    "    seq = Sequential()\n",
    "\n",
    "    seq.add(Convolution2D(64, 5, 5, border_mode='same',\n",
    "                input_shape=input_shape))\n",
    "    seq.add(Activation('relu'))\n",
    "    seq.add(Convolution2D(64, 5, 5))\n",
    "    seq.add(Activation('relu'))\n",
    "    seq.add(MaxPooling2D(pool_size=(5, 5), strides=(2, 2)))\n",
    "    seq.add(Dropout(0.25))\n",
    "\n",
    "    seq.add(Convolution2D(128, 3, 3, border_mode='same'))\n",
    "    seq.add(BatchNormalization())\n",
    "    seq.add(Activation('relu'))\n",
    "    seq.add(Convolution2D(128, 3, 3))\n",
    "    seq.add(BatchNormalization())\n",
    "    seq.add(Activation('relu'))\n",
    "    seq.add(MaxPooling2D(pool_size=(2, 2),strides=(2, 2)))\n",
    "    seq.add(Dropout(0.25))\n",
    "\n",
    "    seq.add(Flatten())\n",
    "    seq.add(Dense(512))\n",
    "    seq.add(Activation('relu'))\n",
    "    return seq\n",
    "\n",
    "\n",
    "def compute_accuracy(predictions, labels):\n",
    "    '''Compute classification accuracy with a fixed threshold on distances.\n",
    "    '''\n",
    "    return labels[predictions.ravel() < 0.5].mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "DistortImg, DistortLabel, RefImg, RefLabel, ScoreLabel = load_data()\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "# create training+test positive and negative pairs\n",
    "'''digit_indices = [np.where(y_train == i)[0] for i in range(10)]\n",
    "tr_pairs, tr_y = create_pairs(X_train, digit_indices)\n",
    "\n",
    "digit_indices = [np.where(y_test == i)[0] for i in range(10)]\n",
    "te_pairs, te_y = create_pairs(X_test, digit_indices)'''\n",
    "\n",
    "all_pairs = create_compare(DistortImg, RefImg)\n",
    "\n",
    "X_train = all_pairs[1:2001]\n",
    "X_test =  all_pairs[2001:3000]\n",
    "\n",
    "Y_train = ScoreLabel[1:2001]\n",
    "Y_test = ScoreLabel[2001:3000]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[151,  52,  25],\n",
       "        [151,  53,  25],\n",
       "        [153,  55,  29],\n",
       "        ..., \n",
       "        [178,  74,  43],\n",
       "        [171,  67,  37],\n",
       "        [156,  53,  25]],\n",
       "\n",
       "       [[154,  55,  27],\n",
       "        [151,  53,  26],\n",
       "        [152,  56,  30],\n",
       "        ..., \n",
       "        [170,  69,  39],\n",
       "        [177,  75,  44],\n",
       "        [163,  59,  31]],\n",
       "\n",
       "       [[154,  55,  28],\n",
       "        [152,  54,  27],\n",
       "        [153,  56,  29],\n",
       "        ..., \n",
       "        [159,  55,  29],\n",
       "        [169,  66,  37],\n",
       "        [171,  68,  39]],\n",
       "\n",
       "       ..., \n",
       "       [[154,  51,  24],\n",
       "        [154,  50,  23],\n",
       "        [151,  55,  30],\n",
       "        ..., \n",
       "        [161,  51,  23],\n",
       "        [161,  52,  24],\n",
       "        [161,  52,  25]],\n",
       "\n",
       "       [[151,  50,  24],\n",
       "        [154,  52,  25],\n",
       "        [153,  58,  32],\n",
       "        ..., \n",
       "        [161,  52,  23],\n",
       "        [160,  51,  24],\n",
       "        [159,  52,  25]],\n",
       "\n",
       "       [[157,  52,  25],\n",
       "        [155,  51,  25],\n",
       "        [155,  57,  31],\n",
       "        ..., \n",
       "        [162,  51,  23],\n",
       "        [161,  52,  24],\n",
       "        [159,  52,  25]]], dtype=uint8)"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "all_pairs[121,1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "X_train /= 255\n",
    "X_test /= 255\n",
    "input_dim = 96,128\n",
    "nb_epoch = 20\n",
    "input_shape = (96,128,1)\n",
    "\n",
    "# network definition\n",
    "base_network = create_base_network(input_shape)\n",
    "\n",
    "input_a = Input(shape=input_shape)\n",
    "input_b = Input(shape=input_shape)\n",
    "\n",
    "# because we re-use the same instance `base_network`,\n",
    "# the weights of the network\n",
    "# will be shared across the two branches\n",
    "processed_a = base_network(input_a)\n",
    "processed_b = base_network(input_b)\n",
    "\n",
    "distance = Lambda(euclidean_distance, output_shape=eucl_dist_output_shape)([processed_a, processed_b])\n",
    "\n",
    "model = Model(input=[input_a, input_b], output=distance)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2000, 96, 128, 1)"
      ]
     },
     "execution_count": 90,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#x_train1 = np.array([X_train[:,0],])\n",
    "\n",
    "x_train1 = np.expand_dims(X_train[:,0], axis=3)\n",
    "x_train2 = np.expand_dims(X_train[:,1], axis=3)\n",
    "x_test1 = np.expand_dims(X_test[:,0], axis=3)\n",
    "x_test2 = np.expand_dims(X_test[:,1], axis=3)\n",
    "\n",
    "x_train1.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 2000 samples, validate on 999 samples\n",
      "Epoch 1/20\n",
      " 288/2000 [===>..........................] - ETA: 726s - loss: nan"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-91-5d087068de03>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      4\u001b[0m           \u001b[0mvalidation_data\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mx_test1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx_test2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mY_test\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m           \u001b[0mbatch_size\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m32\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m           nb_epoch=nb_epoch)\n\u001b[0m",
      "\u001b[0;32m/Users/rwa56/homebrew/lib/python2.7/site-packages/keras/engine/training.pyc\u001b[0m in \u001b[0;36mfit\u001b[0;34m(self, x, y, batch_size, nb_epoch, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch)\u001b[0m\n\u001b[1;32m   1141\u001b[0m                               \u001b[0mval_f\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mval_f\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mval_ins\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mval_ins\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mshuffle\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mshuffle\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1142\u001b[0m                               \u001b[0mcallback_metrics\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcallback_metrics\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1143\u001b[0;31m                               initial_epoch=initial_epoch)\n\u001b[0m\u001b[1;32m   1144\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1145\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mevaluate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbatch_size\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m32\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mverbose\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msample_weight\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/Users/rwa56/homebrew/lib/python2.7/site-packages/keras/engine/training.pyc\u001b[0m in \u001b[0;36m_fit_loop\u001b[0;34m(self, f, ins, out_labels, batch_size, nb_epoch, verbose, callbacks, val_f, val_ins, shuffle, callback_metrics, initial_epoch)\u001b[0m\n\u001b[1;32m    841\u001b[0m                 \u001b[0mbatch_logs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'size'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbatch_ids\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    842\u001b[0m                 \u001b[0mcallbacks\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mon_batch_begin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbatch_index\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbatch_logs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 843\u001b[0;31m                 \u001b[0mouts\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mins_batch\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    844\u001b[0m                 \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mouts\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    845\u001b[0m                     \u001b[0mouts\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mouts\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/Users/rwa56/homebrew/lib/python2.7/site-packages/keras/backend/theano_backend.pyc\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, inputs)\u001b[0m\n\u001b[1;32m    917\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__call__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minputs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    918\u001b[0m         \u001b[0;32massert\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minputs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mlist\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 919\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfunction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0minputs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    920\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    921\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/Users/rwa56/homebrew/lib/python2.7/site-packages/theano/compile/function_module.pyc\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m    857\u001b[0m         \u001b[0mt0_fn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    858\u001b[0m         \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 859\u001b[0;31m             \u001b[0moutputs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    860\u001b[0m         \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    861\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0mhasattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'position_of_error'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/Users/rwa56/homebrew/lib/python2.7/site-packages/theano/gof/op.pyc\u001b[0m in \u001b[0;36mrval\u001b[0;34m(p, i, o, n)\u001b[0m\n\u001b[1;32m    909\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mparams\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0mgraph\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mNoParams\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    910\u001b[0m             \u001b[0;31m# default arguments are stored in the closure of `rval`\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 911\u001b[0;31m             \u001b[0;32mdef\u001b[0m \u001b[0mrval\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mi\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mnode_input_storage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mo\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mnode_output_storage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mnode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    912\u001b[0m                 \u001b[0mr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mp\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mx\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mo\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    913\u001b[0m                 \u001b[0;32mfor\u001b[0m \u001b[0mo\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moutputs\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "rms = RMSprop()\n",
    "model.compile(loss=contrastive_loss, optimizer=rms)\n",
    "model.fit( [x_train1, x_train2], Y_train,\n",
    "          validation_data=([x_test1, x_test2], Y_test),\n",
    "          batch_size=32,\n",
    "          nb_epoch=nb_epoch)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
